from django.contrib.gis.db.models import *
from django.template import RequestContext
from django.shortcuts import render_to_response
from django.contrib.auth import login,logout
from django.contrib.auth.models import User
from django.http import HttpResponse
from django.core.exceptions import ObjectDoesNotExist
from django.contrib import flatpages
from django.contrib.auth import views as auth_views
from django.contrib.gis.gdal import DataSource
from django.contrib.gis.geos import *
from django.core.cache import cache
from ce_atlas_app import models
import settings

import mapscript
import os,sys,re,datetime,os.path,zipfile

from util import *
from PIL import Image

import logging
logging.basicConfig(
    level = logging.DEBUG,
    format = '%(asctime)s %(levelname)s %(message)s',
)

# cache the media types
MEDIA_TYPES_BY_NAME = {}
MEDIA_TYPES = models.media_type.objects.all()
for m in MEDIA_TYPES:
    MEDIA_TYPES_BY_NAME[m.name] = m

# Aggregates CE_ATLAS js files into one with minifying, 
# reducing the file size, but making it difficult to debug on the client
def jsmin(request):
    js = "" 
    #Minify by default, but leave it full text for debugging if requested using the minify=false param
    for file in settings.SCRIPTS:
        js = js + os.popen("cat "+settings.MEDIA_ROOT+"/js/%s | jsmin"%file).read()
    return HttpResponse(js,mimetype="text/javascript")    

def ajaxRsp(body):
    #response = HttpResponse(body,mimetype='application/json')
    response = HttpResponse(body,mimetype='text/plain')
    response['Cache-Control'] = "no-cache"
    response['Pragma'] = 'no-cache'
    response['Expires'] = '-1'
    return response
    
def index(request):
    
    tv = {
        'settings':settings,
        'auth': 'false'
    } # template values.
    
    active_group = get_group_config(request).group
    
    #ensure user is in the active group. if not, log them out.
    if request.user.is_authenticated():
    
        is_anon = request.user.first_name == "Anonymous"
        in_group = active_group in request.user.groups.all()
        
        if not is_anon and in_group:
            tv['auth'] = 'true'
        
        # don't allow anonymous users from the wrong group.
        if is_anon and not in_group:
            logout(request)
        
    # if user isn't logged in, log them in as the anonymous user for this group.
    if not request.user.is_authenticated():
        anon_user = get_anon_user(active_group)
        anon_user.backend = 'django.contrib.auth.backends.ModelBackend'
        login(request,anon_user)
    
    tv['user'] = request.user

    #tv['about'] = flatpages.models.FlatPage.objects.get(url='/about/').content

    #tv['about_title'] = flatpages.models.FlatPage.objects.get(url='/about/').title
    
    tv['media_types'] = django2json(MEDIA_TYPES)

    tv['formats'] = django2json(models.wms_format.objects.order_by('id'))
    
    # there's no use doing .order_by, because django2json re-orders by id anyway
    tv['themes'] = django2json(models.theme.objects.filter(
        groups=active_group
    ),None,['sub_themes'])

    tv['places'] = django2json(models.place.objects.filter(
        groups=active_group
    ).order_by('title'),None,['sub_places'])

    return render_to_response('index.html', RequestContext(request, tv))

def delete_media(request,id):
    try:
        media_item = models.media.objects.get(pk=int(id))
        user_shapes = media_item.user_shapes
        media_item.delete()
        if user_shapes and models.media.objects.filter(user_shapes=user_shapes).count() == 0:
            user_shapes.delete()
    except:
        return ajaxRsp('{success:false,errorMsg:"%s"}'%sys.exc_info())
    return ajaxRsp('{success:true}')


def generate_error_html(msg):
    return '''<html>
                   <head>
                   <script type="text/javascript">
                   function goBack()
                   {
                        parent.CE.MEDIA.ADD.defer_dialog();
                   }
                   </script>
                   </head>
                   <body>''' + msg + '''<br/>
                   <input type="button" value="Back" onclick="goBack()" />
                   </body></html>'''


def upload_shape_file(request):
    
    theme_id = request.POST['theme']
    theme = models.theme.objects.get(id=int(theme_id))
    file = request.FILES.has_key('image') and request.FILES['image']
    content = request.POST['content']

    if file and file.name:
        filename = file.name
        filepath = None
        idx = 0
        while not filepath or os.path.exists(filepath):
            parts = os.path.splitext(filename)
            filename = parts[0] + str(idx) + parts[1]
            filepath = os.path.join('/tmp/',filename)
            idx += 1
            
        filetype = file_extension(filename.lower())
        is_zip = filetype == 'zip'
        if not is_zip:
            return HttpResponse(generate_error_html("Please upload a ZIP file."));

        try:
            zfile = zipfile.ZipFile(file, 'r')
            corr_extensions = ['dbf', 'prj', 'shp', 'shx']
            extensions = [file_extension(i.lower()) for i in zfile.namelist()]
            good_zip_file = True
            shp_filename = ''
            for ce in corr_extensions:
                if ce not in extensions:
                    good_zip_file = False
                    break
            if not good_zip_file:
                return HttpResponse(generate_error_html("ZIP file should include the following files: .shp, .shx, .dbf, .prj"));
        except:
            return HttpResponse(generate_error_html("Invalid ZIP file."));
        if True:
            for name in zfile.namelist():
                data = zfile.read(name)
                fname = re.sub(r'[^a-zA-Z\d\.]', '', name.lower())
                path = os.path.join('/tmp/', fname)
                if file_extension(fname) == 'shp':
                    shp_filename = fname
                fd = open(path, 'wb')
                fd.write(data)
                fd.close()
                os.chmod(path, 0777)
                
            ########################################
            description = request.POST['content']
            title=request.POST['title'] 
            source=request.POST['source']
            date_start=date_or_null(request.POST['date_start'])
            date_end=date_or_null(request.POST['date_end'])

            ds = DataSource(os.path.join('/tmp/',shp_filename))
            shapes = []
            for layer in ds:
                for feature in layer:
                    fields = {}
                    for fn in feature.fields:
                        if type(fn) == str:
                            fn = "".join(filter(lambda x: ord(x)<128, fn))
                        fields[fn] = feature.get(fn)
                        if type(fields[fn]) == str:
                            fields[fn] = "".join(filter(lambda x: ord(x)<128, fields[fn]))
                    fields_str = simplejson.dumps(fields)
                    trans_geom = feature.geom.transform(4326,clone=True)
                    new_geo_collection = GEOSGeometry(trans_geom.wkt)
                    shapes.append(new_geo_collection)

            new_shape = GeometryCollection(shapes)
            uus = models.UserUploadedShapes(geoms=new_shape,attributes=fields_str,title=title,description=description,theme=theme,source=source,start_date=date_start,end_date=date_end,style='{}')
            uus.save()
            shapes_json = render_to_geojson([uus], models.UserUploadedShapes, 'geoms', raw=True)
            return upload_template(str(shapes_json),'')

    else: 
        return upload_template('{success:False}',generate_error_html("Please upload a valid ZIP file."));

def upload_media(request): 
    
    theme_list = eval(request.POST['themes'])
    theme = models.theme.objects.get(id=theme_list[0])
    type_name = request.POST['type']
    kind = None
    if type_name.strip() != '':
        kind = MEDIA_TYPES_BY_NAME[type_name]
    file = request.FILES.has_key('image') and request.FILES['image']
    content = request.POST['content']
    shape_wkt = request.POST['shape']
    user_shapes = None
    if len(shape_wkt.strip()) != 0:
        if len(shape_wkt.strip()) > 12 and shape_wkt[:12] == "UserShapeID:":
            user_shapes = models.UserUploadedShapes.objects.get(id = int(shape_wkt[12:]))
        else:
            new_geo = GEOSGeometry(shape_wkt)
            new_geo_collection = GeometryCollection([new_geo])
            user_shapes = models.UserUploadedShapes(geoms=new_geo_collection,attributes='',style='{}')
            user_shapes.save()
    
    if file and file.name:
        filename = re.sub(r'[^a-zA-Z\d\.]', '', file.name)
        filepath = None
        idx = 0
        while not filepath or os.path.exists(filepath):
            parts = os.path.splitext(filename)
            filename = parts[0] + str(idx) + parts[1]
            filepath = os.path.join(settings.USER_DATA,filename)
            idx += 1
            
        fileurl = os.path.join("/data",re.sub(r'[^a-zA-Z\d\.]', '', filename))
        filetype = file_extension(filename.lower())
        is_image = filetype in ['gif','png','jpeg','jpg']

        fd = open(filepath, 'wb')
        for chunk in file.chunks():
            fd.write(chunk)
        fd.close()
        
        if is_image:
            if not kind:
                kind = MEDIA_TYPES_BY_NAME['photo']
            content = '<img src="%s" />'%fileurl + content
            # generate thumbnails.
            im = Image.open(filepath)
            width, height = im.size 
            if width > 800: 
                im.save(filepath+'.bak', "JPEG") 
                im.resize((800,int(800*width/height)))
                im.save(filepath)
                im.thumbnail((128,128))
                im.save(os.path.splitext(filepath)[0]+'.thumbnail.jpg', "JPEG")
        else:
            if not kind:
                if filetype in ['ogg','mp3','wav','midi']:
                    kind = MEDIA_TYPES_BY_NAME['sound']
                elif filetype in ['mp4','mov','swf','avi','mpg','mpeg']:
                    kind = MEDIA_TYPES_BY_NAME['movie']
                else:
                    kind = MEDIA_TYPES_BY_NAME['story']
            content = content + '<br/><br/>attachment: <a target="_blank" href="%s">%s</a>'%(fileurl,filename)
            
            # TODO: detect charts.
    elif not kind:
       if '<embed' in content:
          kind = MEDIA_TYPES_BY_NAME['movie']
       else:
          kind = MEDIA_TYPES_BY_NAME['story']
    new_media = models.media(
        title=request.POST['title'],  
        source=request.POST['source'],
        content=content,
        latitude=float_or_null(request.POST['latitude']),
        longitude=float_or_null(request.POST['longitude']),
        date_start=date_or_null(request.POST['date_start']),
        date_end=date_or_null(request.POST['date_end']),
        type=kind,
        remote_address=request.META['REMOTE_ADDR'], 
        owner = request.user,
        user_shapes = user_shapes
    )
    new_media.save()
    new_media.themes.add(theme)

    py_media = first_item(django2python([new_media], None, ["user_shapes"]))
    py_media['themes'] = theme_list
    
    return upload_template('{"success":true,"media_item":' + simplejson.dumps(py_media) + '}', '')

def upload_template(content, error_text):

    return HttpResponse('''
<html><head>
</head>
<body><div class="json" style="display:none">
//<!--
''' + content + '''
//-->
</div>''' + error_text + '''</body></html>
''', mimetype = 'text/html')


def get_media(request):
    return ajaxRsp(django2json(models.media.objects.order_by('id'),None,['themes', 'user_shapes']))

def get_wms_layers(request):

    req = mapscript.OWSRequest()
    map = mapscript.mapObj(settings.MAPFILE)
    
    #add the mapfile connection parameter into the layers so chained layers' legend graphic can be loaded.
    py_layers = django2python(models.wms_layer.objects.filter(themes__groups__in=request.user.groups.all()).order_by('order'),None,['themes'])
    for id in py_layers.keys():
        layer = map.getLayerByName(py_layers[id]['layers'])
        if layer and layer.connection and 'http://' in layer.connection:
            py_layers[id]['connection'] = layer.connection
            
    return ajaxRsp( simplejson.dumps(py_layers))

def get_wfs_layers(request):
    py_layers = django2python(models.wfs_layer.objects.filter(themes__groups__in=request.user.groups.all()).order_by('order'),None,['themes'])
    return ajaxRsp( simplejson.dumps(py_layers))

def get_user_uploaded_shapes(request):
    
    cache_json = cache.get('user_uploaded_shapes')
    if cache_json:
        shapes_json = cache_json
    else:
        shapes = models.UserUploadedShapes.objects.all()
        shapes_json = render_to_geojson(shapes, models.UserUploadedShapes, 'geoms')
        cache.set('user_uploaded_shapes', str(shapes_json), 1800)

    return ajaxRsp(str(shapes_json))


'''
deprecated.
'''
def get_rectified_wms_image(request, filename):

    req = mapscript.OWSRequest()

    mime = request.GET['FORMAT']
    req.setParameter("bbox", request.GET['BBOX'])
    req.setParameter("width", request.GET['WIDTH'])
    req.setParameter("height", request.GET['HEIGHT'])
    req.setParameter("srs", request.GET['SRS'])
    req.setParameter("format", mime)
    req.setParameter("layers", request.GET['LAYERS'])
    req.setParameter("request", request.GET['REQUEST'])
    
    map = mapscript.mapObj(settings.PRIVATE_MAPFILE)
    
    img_layer = map.getLayerByName('rectified_image')
    img_layer.data = os.path.join(settings.IMAGE_DIR, filename)

    map.loadOWSParameters(req)
    
    image = map.draw().getBytes()
    response = HttpResponse()
    response['Content-length'] = len(image)
    response['Content-Type'] = mime
    response.write(image)
    return response
    
def get_layer_data(request, table_name):
    ''' direct json interface to sql database for getting layer data '''
    from django.db import connection
    cursor = connection.cursor()             
    sql= 'SELECT * from %s' % table_name 
    cursor.execute(sql)
    result = cursor.fetchall()

    return ajaxRsp(simplejson.dumps({
      'result' : result,
      'meta' : cursor.description
    }))

def get_fonts(request):
    fontfiledir = os.path.join(settings.ROOT, 'mapserver/etc/fonts.txt')
    fontfile = open(fontfiledir)
    fonts = [line.split(' ')[0] for line in fontfile.readlines()]
    if "" in fonts:
        fonts.remove("")
    fontfile.close()

    return ajaxRsp(simplejson.dumps({
      'fonts' : fonts
    }))



